/*  - Código para o Cliente da Agenda */
/*------------------------------------------------------------------------
 * Programa:  AgendaCLIENT.c
 *
 * Proposta:  Criar um socket para conectar ao servidor e transmitir os
 *            comando para controle da agenda.
 *
 * Sintaxe:   AgendaCLIENT host port username password <COMMAND>
 *            ADD <DATA> <HORA_INICIO> <HORA_FIM> <INFORMAÇÃO>
 *            REMOVE <DATA> <HORA_INICIO>
 *            REMOVE <DATA> ALL
 *            UPDATE <DATA> <HORA_INICIO> <HORA_FIM> <INFORMAÇÃO>
 *            GET <DATA> <HORA_INICIO>
 *            GET <DATA> ALL
 *            
 *            <DATA> DDMMYYYY ==> 20072010
 *            <HORA_*> HHMM ==> 0800
 *
 *------------------------------------------------------------------------
 */
#include "auxiliar.h"

int main(int argc, char *argv[])
{
    struct  hostent  *ptrh;  /* pointer to a host table entry       */
    struct  protoent *ptrp;  /* pointer to a protocol table entry   */
    struct  sockaddr_in sad; /* structure to hold an IP address     */
    int     sd;              /* socket descriptor                   */
    int     n, loops;               /* number of characters read           */
    char    buf[1000];       /* buffer for data from the server     */

    #ifdef WIN32
    WSADATA wsaData;
    WSAStartup(0x0101, &wsaData);
    #endif

    memset((char *)&comando,0,sizeof(comando)); /* Zerando a estrutura de comando */
    memset((char *)&sad,0,sizeof(sad)); /* clear sockaddr structure */
    sad.sin_family = AF_INET;         /* set family to Internet     */

    if(argc < 5){
        fprintf(stdout, ERRO_MSG, 1 , ERRO_01);
        exit(1);
    }

    strcpy(comando.host, argv[1]);

    porta = atoi(argv[2]);
    if(porta > 0) {
        comando.porta = porta;
    } else {
        fprintf(stdout, ERRO_MSG, 1 , ERRO_02);
        exit(2);
    }
    
    // Valida username.
    n = matchUsername(argv[3]);
    if(n != 1){
        fprintf(stdout, ERRO_MSG, 8 , ERRO_08);
        exit(8);
    }
    strcpy(comando.usuario, argv[3]);

    // Valida password.
    n = strlen(argv[4]);
    if ( n > 20 || n <= 0 ){
        fprintf(stdout, ERRO_MSG, 9 , ERRO_09);
        exit(9);
    }
    strcpy(comando.senha, argv[4]);
    
    
    // Comando de Login
    if( strcmp(argv[5],"LOGIN") == 0){
        if ( argc != 6 ){
            fprintf(stdout, ERRO_MSG, 1 , ERRO_01);
            exit(1);
        }
        comando.protocolo = 1;
        sprintf(comando.comandos, "%d;%s;%s;",1,comando.usuario,comando.senha);
    }
    // Comando de Inclusão
    else if( strcmp(argv[5],"ADD") == 0 ) {
        if ( argc != 10 ){
            fprintf(stdout, ERRO_MSG, 1 , ERRO_01);
            exit(1);
        }
        comando.protocolo = 2;
        comandoAdd(&comando, argv[6], argv[7], argv[8], argv[9]);
    }
    // Comando de Remoção
    else if( strcmp(argv[5],"REMOVE") == 0 ) {
        if ( argc != 8 ){
            fprintf(stdout, ERRO_MSG, 1 , ERRO_01);
            exit(1);
        }
    
        if ( strcmp(argv[7],"ALL") == 0  ) {
            comando.protocolo = 3;
            comandoRemoveAll(&comando,argv[6]);
        } else {
            comando.protocolo = 4;
            comandoRemove(&comando,argv[6],argv[7]);
        }
    }
    // Comando de Update
    else if( strcmp(argv[5],"UPDATE") == 0 ) {
        if ( argc != 10 ){
            fprintf(stdout, ERRO_MSG, 1 , ERRO_01);
            exit(1);
        }
        comando.protocolo = 5;
        comandoUpdate(&comando, argv[6], argv[7], argv[8], argv[9]);
    }
    // Comando de Get
    else if( strcmp(argv[5],"GET") == 0 ) {
        if ( argc != 8 ){
            fprintf(stdout, ERRO_MSG, 1 , ERRO_01);
            exit(1);
        }

        if ( strcmp(argv[7],"ALL") == 0  ) {
            comando.protocolo = 7;
            comandoGetAll(&comando,argv[6]);
        } else {
            comando.protocolo = 6;
            comandoGet(&comando,argv[6],argv[7]);
        }
    }
    // Não se encaixou em nenhuma regra anterior ERRO.
    else {
        fprintf(stdout, ERRO_MSG, 6 , ERRO_06);
        exit(6);
    }

    /* Aqui já temos o comando pronto para enviar      
       Iniciando a parte de comunicação com o Servidor */

    /* Fazendo o bind com a porta */
    sad.sin_port = htons((u_short)comando.porta);

    /* Converte o hostname para um endereço de IP 
       equivalente e o copia para a esturura. */
    ptrh = gethostbyname(comando.host);
    if ( ((char *)ptrh) == NULL ) {
        fprintf(stdout,"Erro 8\n-----------\nO hostname [ %s ] eh invalido.\n", comando.host);
        exit(8);
    }

    memcpy(&sad.sin_addr, ptrh->h_addr, ptrh->h_length);
        
    /* Mapear o nome do protocolo de transporte TCP
        para seu número. */
    if ( ((int)(ptrp = getprotobyname("tcp"))) == 0) {
        fprintf(stdout, "Erro 8\n-----------\nNao foi possivel mapear o protocolo de  \"tcp\" para seu numero.\n");
        exit(9);
    }

    /* Criando um socket. */
    sd = socket(PF_INET, SOCK_STREAM, ptrp->p_proto);
    if (sd < 0) {
        fprintf(stdout, "Erro 10\n-----------\nFalha ao criar o socket.\n");
        exit(10);
    }

    /* Conectando o socket ao servidor. */
    if (connect(sd, (struct sockaddr *)&sad, sizeof(sad)) < 0) {
        fprintf(stdout,"Erro 10\n-----------\nA conexao falhou.\n");
        exit(11);
    }
    
    /* Parte de comunicação com o software. */
    //Enviando comando
    send(sd, comando.comandos, strlen(comando.comandos), 0);
    fprintf(stdout, "# Comando enviado...\n");

    /* Resposta Handler */
    memset(buf,0, 1000);
    switch(comando.protocolo){
        case LOGIN:
            {
                n = recv(sd, buf, sizeof(buf), 0);
                if ( n <= 0 ) {
                    fprintf(stdout, ERRO_MSG, 10 , ERRO_10);
                    exit(10);
                }
                handlerRetorno(buf,"LOGIN");
                break;
            }
        case ADD:
            {
                n = recv(sd, buf, sizeof(buf), 0);
                if ( n <= 0 ) {
                    fprintf(stdout, ERRO_MSG, 10 , ERRO_10);
                    exit(10);
                }
                handlerRetorno(buf,"ADD");
                break;
            }
        case REMOVEALL:
            {
                n = recv(sd, buf, sizeof(buf), 0);
                if ( n <= 0 ) {
                    fprintf(stdout, ERRO_MSG, 10 , ERRO_10);
                    exit(10);
                }
                handlerRetorno(buf,"REMOVEALL");
                break;
            }
        case REMOVE:
            {
                n = recv(sd, buf, sizeof(buf), 0);
                if ( n <= 0 ) {
                    fprintf(stdout, ERRO_MSG, 10 , ERRO_10);
                    exit(10);
                }
                handlerRetorno(buf,"REMOVE");
                break;
            }
        case UPDATE:
            {
                n = recv(sd, buf, sizeof(buf), 0);
                if ( n <= 0 ) {
                    fprintf(stdout, ERRO_MSG, 10 , ERRO_10);
                    exit(10);
                }
                handlerRetorno(buf,"UPDATE");
                break;
            }
        case GET:
            {
                n = recv(sd, buf, sizeof(buf), 0);
                if ( n <= 0 ) {
                    fprintf(stdout, ERRO_MSG, 10 , ERRO_10);
                    exit(10);
                }
                handlerRetornoGet(buf, "GET");
                break;
            }
        case GETALL:
            {
                memset(buf,'\0', 1000);
                n = recv(sd, buf, sizeof(buf), 0);
                if ( n <= 0 ) {
                    fprintf(stdout, ERRO_MSG, 10 , ERRO_10);
                    exit(10);
                }

                loops = handlerRetornoGetAllQtde(buf, "GETALL");
            
                do
                {
                    memset(buf,'\0', 1000);
                    n = recv(sd, buf, sizeof(buf), 0);
                    if ( n <= 0 ) {
                        fprintf(stdout, ERRO_MSG, 10 , ERRO_10);
                        exit(10);
                    }
                    handlerRetornoGetAll(buf);
                }while(--loops>0);
                break;
            }
        default:
            {
                fprintf(stdout, "Protocolo Inválido.\n");
                break;
            } 
    }



    /* Fechando o socket. */
    closesocket(sd);

    /* Terminando o programa e esvaziando pilhas e fechando conexões. */
    fprintf(stdout,"#\n#Saindo graciosamente.\n");
    exit(0);
}
